
#include <xgba_p.h>
#include <xgba.h>
#include <string.h>
#include <xgba_cpu.h>
#include <xgba_mem.h>
#include <xgba_vram.h>
#include <stdlib.h>
#include <stdio.h>

int xgba_init(xgba_t*gba){
    memset(gba,0,sizeof(*gba));
    return 0;
}

int xgba_loadrom(xgba_t*gba,const uint8_t*data){
    xgba_loadrom_free(gba,(uint8_t*)data,0);
    return 0;
}

int xgba_vram_init(xgba_t*gba);
static void set_io(xgba_t*gba,uint32_t address,uint32_t value,int size);
int xgba_loadrom_free(xgba_t*gba,uint8_t*data,void (*_free)(void*data)){
    gba->rom = (uint8_t*)data;
    gba->rom_free = _free;

    /*
    初始化ROM
    PC被设置为0x08000000,一般默认为bios起始

    */
    gba->R[arm_pc] = 0x08000000;

    gba->mem_map[0x0] = &gba->bios[0];
    gba->mem_map[0x2] = &gba->wram[0];
    gba->mem_map[0x3] = &gba->iram[0];
    gba->mem_map[0x4] = &gba->io[0];
    gba->mem_map[0x5] = &gba->pal[0];
    gba->mem_map[0x6] = &gba->vram[0];
    gba->mem_map[0x7] = &gba->oam[0];
    gba->mem_map[0x8] = &gba->rom[0];
    gba->mem_map[0x9] = &gba->rom[0x1000000];
    gba->mem_map[0xa] = &gba->rom[0];
    gba->mem_map[0xb] = &gba->rom[0x1000000];
    gba->mem_map[0xc] = &gba->rom[0];
    gba->mem_map[0xd] = &gba->rom[0x1000000];
    gba->mem_map[0xe] = &gba->sram[0];

    gba->mem_map[0x1] = &gba->nullmem[0];
    gba->mem_map[0xf] = &gba->nullmem[0];

    gba->mem_map_mask[0x0] = 0x3fff;
    gba->mem_map_mask[0x2] = 0x3ffff;
    gba->mem_map_mask[0x3] = 0x7fff;
    gba->mem_map_mask[0x4] = 0x3ff;
    gba->mem_map_mask[0x5] = 0x3ff;
    gba->mem_map_mask[0x6] = 0x1ffff;
    gba->mem_map_mask[0x7] = 0x3ff;
    gba->mem_map_mask[0x8] = 0x1ffffff;
    gba->mem_map_mask[0x9] = 0x1ffffff;
    gba->mem_map_mask[0xa] = 0x1ffffff;
    gba->mem_map_mask[0xb] = 0x1ffffff;
    gba->mem_map_mask[0xc] = 0x1ffffff;
    gba->mem_map_mask[0xd] = 0x1ffffff;
    gba->mem_map_mask[0xe] = 0xffff;

    gba->w_mem_map[0x0] = &gba->nullmem[0];
    gba->w_mem_map[0x2] = &gba->wram[0];
    gba->w_mem_map[0x3] = &gba->iram[0];
    gba->w_mem_map[0x4] = &gba->wio[0];
    gba->w_mem_map[0x5] = &gba->pal[0];
    gba->w_mem_map[0x6] = &gba->vram[0];
    gba->w_mem_map[0x7] = &gba->oam[0];
    gba->w_mem_map[0x8] = &gba->nullmem[0];
    gba->w_mem_map[0x9] = &gba->nullmem[0];
    gba->w_mem_map[0xa] = &gba->nullmem[0];
    gba->w_mem_map[0xb] = &gba->nullmem[0];
    gba->w_mem_map[0xc] = &gba->nullmem[0];
    gba->w_mem_map[0xd] = &gba->nullmem[0];
    gba->w_mem_map[0xe] = &gba->sram[0];

    gba->w_mem_map[0x1] = &gba->nullmem[0];
    gba->w_mem_map[0xf] = &gba->nullmem[0];

    gba->w_mem_map_mask[0x0] = 0x0;
    gba->w_mem_map_mask[0x2] = 0x3ffff;
    gba->w_mem_map_mask[0x3] = 0x7fff;
    //gba->w_mem_map_mask[0x4] = 0x3ff;
    gba->w_mem_map_mask[0x4] = 0x0;     //关闭写入io,采取仿真中断处理io操作
    gba->w_mem_map_mask[0x5] = 0x3ff;   //16/32
    gba->w_mem_map_mask[0x6] = 0x1ffff; //16/32
    gba->w_mem_map_mask[0x7] = 0x3ff;   //16/32
    gba->w_mem_map_mask[0x8] = 0x0;
    gba->w_mem_map_mask[0x9] = 0x0;
    gba->w_mem_map_mask[0xe] = 0xffff;

    #define SET_CYCLES(idx,u8,u16,u32) \
    gba->read_cycles[idx][0] = u8; \
    gba->read_cycles[idx][1] = u16; \
    gba->read_cycles[idx][2] = u32;

    SET_CYCLES(0x0,1,1,1);
    SET_CYCLES(0x3,1,1,1);
    SET_CYCLES(0x4,1,1,1);

    /*如果与内部硬件同时访问vram,则增加一个时钟周期*/
    SET_CYCLES(0x5,1,1,2);
    SET_CYCLES(0x6,1,1,2);
    SET_CYCLES(0x7,1,1,1);

    /*会根据waitstate设置来设置时钟周期,2,8,9,e*/
    SET_CYCLES(0x2,3,3,6);
    SET_CYCLES(0x8,5,5,8);
    SET_CYCLES(0x9,5,5,8);
    SET_CYCLES(0xe,5,5,5);

    //设置WAITCNT

    /*16位执行代码*/
    gba->exec_cycles[0x00][1] = 0;
    gba->exec_cycles[0x01][1] = 0;
    gba->exec_cycles[0x02][1] = 0;
    gba->exec_cycles[0x03][1] = 0;
    gba->exec_cycles[0x05][1] = 0;
    gba->exec_cycles[0x06][1] = 0;
    gba->exec_cycles[0x07][1] = 0;


    gba->exec_cycles32[0x00][2] = 0;
    gba->exec_cycles32[0x01][2] = 0;
    gba->exec_cycles32[0x02][2] = 0;
    gba->exec_cycles32[0x03][2] = 0;
    gba->exec_cycles32[0x05][2] = 0;
    gba->exec_cycles32[0x06][2] = 0;
    gba->exec_cycles32[0x07][2] = 0;

    set_io(gba,0x04000204,0x0,2);

    gba->R[arm_svc_r13] = 0x03007fe0;
    gba->R[arm_irq_r13] = 0x03007fa0;
    gba->R[arm_r13] = 0x03007f00;
    gba->R[arm_cpsr] = 0x1f;

    REG_SETXGBA(gba->R,gba);

    uint32_t *pixels = calloc(1,241*160*4);
    void **pixels_line = calloc(1,160*sizeof(void*));
    int i;
    gba->screen = (uint32_t**)pixels_line;
    for(i=0;i<160;i++){
        //处理屏幕线
        gba->screen[i] = pixels + i*240;
    }

    xgba_vram_init(gba);

    for(i=0;i<0x400;i+=8){
        gba->oam[i+0] = 0xa0;
    }


    /*初始化io*/
    gba->io[0x00] = 0x80;

    return 0;
}

extern void xgba_clean(xgba_t*gba){
    xgba_close(gba);
}

extern int xgba_close(xgba_t*gba){
    if(gba->rom_free)
        gba->rom_free(gba->rom);
}

extern int xgba_loadbios(xgba_t*gba,const uint8_t*bios_data){
    if(bios_data){
        memcpy(gba->bios,bios_data,sizeof(gba->bios));
    }
    return 0;
}

extern void thumb_exec(uint32_t *R, uint32_t insn);
extern int arm_exec(uint32_t *reg,uint32_t insn);

INLINE void proc_cycles(uint32_t*R,uint32_t address,int mem_type){
    xgba_t*gba = REG_GETXGBA(R);
    int mem = (address>>24)&0xf;
    R[arm_cycles] += gba->read_cycles[mem][mem_type];
}

extern uint32_t read_u32 (uint32_t*R,uint32_t address){
    proc_cycles(R,address,2);
    return xgba_readu32(REG_GETXGBA(R),address);
}
extern uint32_t read_u16 (uint32_t*R,uint32_t address){
    proc_cycles(R,address,1);
    return xgba_readu16(REG_GETXGBA(R),address);
}
extern uint32_t read_u8  (uint32_t*R,uint32_t address){
    proc_cycles(R,address,0);
    return xgba_readu8(REG_GETXGBA(R),address);
}
extern uint32_t read_s16 (uint32_t*R,uint32_t address){
    proc_cycles(R,address,1);
    return xgba_reads16(REG_GETXGBA(R),address);
}
extern uint32_t read_s8  (uint32_t*R,uint32_t address){
    proc_cycles(R,address,0);
    return xgba_reads8(REG_GETXGBA(R),address);
}


extern uint32_t nocycles_read_u32 (uint32_t*R,uint32_t address){
    proc_cycles(R,address,2);
    return xgba_readu32(REG_GETXGBA(R),address);
}
extern uint32_t nocycles_read_u16 (uint32_t*R,uint32_t address){
    proc_cycles(R,address,1);
    return xgba_readu16(REG_GETXGBA(R),address);
}
extern uint32_t nocycles_read_u8  (uint32_t*R,uint32_t address){
    proc_cycles(R,address,0);
    return xgba_readu8(REG_GETXGBA(R),address);
}
extern uint32_t nocycles_read_s16 (uint32_t*R,uint32_t address){
    proc_cycles(R,address,1);
    return xgba_reads16(REG_GETXGBA(R),address);
}
extern uint32_t nocycles_read_s8  (uint32_t*R,uint32_t address){
    proc_cycles(R,address,0);
    return xgba_reads8(REG_GETXGBA(R),address);
}

extern void write_u32    (uint32_t*R,uint32_t rd,uint32_t address){
    R[emu_state] |= ((address>>24)==0x4)<<EMU_STATE_IO_WRITE;
    R[emu_write_address] = address;
    R[emu_write_value] = rd;
    R[emu_write_type] = 4;
    proc_cycles(R,address,2);
    xgba_writeu32(REG_GETXGBA(R),address,rd);
}
extern void write_u16    (uint32_t*R,uint32_t rd,uint32_t address){
    R[emu_state] |= ((address>>24)==0x4)<<EMU_STATE_IO_WRITE;
    R[emu_write_address] = address;
    R[emu_write_value] = rd;
    R[emu_write_type] = 2;
    proc_cycles(R,address,1);
    xgba_writeu16(REG_GETXGBA(R),address,rd);
}
extern void write_u8     (uint32_t*R,uint32_t rd,uint32_t address){
    R[emu_state] |= ((address>>24)==0x4)<<EMU_STATE_IO_WRITE;
    R[emu_write_address] = address;
    R[emu_write_value] = rd;
    R[emu_write_type] = 1;
    proc_cycles(R,address,0);
    xgba_writeu8(REG_GETXGBA(R),address,rd);
}
extern void write_u64    (uint32_t*R,uint32_t rd,uint32_t address){
    xgba_writeu32(REG_GETXGBA(R),address,rd);
}
extern void read_u64     (uint32_t*R,uint32_t rd,uint32_t address){

}
extern void cpu_undefined_instruction(uint32_t*R){
}

extern void cpu_bkpt(uint32_t*R,int imm){
    R[arm_bkpt] = imm;
}

static void switch_mode(uint32_t*R,int oldmode){
    int newmode = R[arm_cpsr];
    oldmode &= 0x1f;
    newmode &= 0x1f;
    if(oldmode==0b11111){
        //离开sys模式
        R[arm_save_r0 + 8] = R[arm_r0 + 8];
        R[arm_save_r0 + 9] = R[arm_r0 + 9];
        R[arm_save_r0 +10] = R[arm_r0 +10];
        R[arm_save_r0 +11] = R[arm_r0 +11];
        R[arm_save_r0 +12] = R[arm_r0 +12];
        R[arm_save_r0 +13] = R[arm_r0 +13];
        R[arm_save_r0 +14] = R[arm_r0 +14];
        R[arm_save_r0 +15] = R[arm_r0 +15];
        R[arm_save_r0 + arm_spsr] = R[arm_spsr];
        //处理lr
    }
    else if(oldmode==arm_mode_svc){
        //离开svc模式
        R[arm_svc_r13] = R[arm_r13];
        R[arm_svc_r14] = R[arm_r14];
        R[arm_svc_spsr] = R[arm_spsr];
    }
    else if(oldmode==arm_mode_irq){
        R[arm_irq_r13] = R[arm_r13];
        R[arm_irq_r14] = R[arm_r14];
        R[arm_irq_spsr] = R[arm_spsr];
    }
    else if(oldmode==arm_mode_fiq){
        //离开fiq模式
        R[arm_fiq_r8] = R[arm_r8];
        R[arm_fiq_r9] = R[arm_r9];
        R[arm_fiq_r10] = R[arm_r10];
        R[arm_fiq_r11] = R[arm_r11];
        R[arm_fiq_r12] = R[arm_r12];
        R[arm_fiq_r13] = R[arm_r13];
        R[arm_fiq_r14] = R[arm_r14];
        R[arm_fiq_spsr] = R[arm_spsr];
    }

    if(newmode==arm_mode_svc){
        //进入svc模式
        R[arm_lr] = R[arm_svc_r14];
        R[arm_sp] = R[arm_svc_r13];
        R[arm_spsr] = R[arm_svc_spsr];
    }
    else if(newmode==arm_mode_abt){
        //进入abt模式
        R[arm_lr] = R[arm_abt_r14];
        R[arm_sp] = R[arm_abt_r13];
        R[arm_spsr] = R[arm_abt_spsr];
    }
    else if(newmode==arm_mode_fiq){
        //进入fiq模式
        R[arm_r8] = R[arm_fiq_r8];
        R[arm_r9] = R[arm_fiq_r9];
        R[arm_r10] = R[arm_fiq_r10];
        R[arm_r11] = R[arm_fiq_r11];
        R[arm_r12] = R[arm_fiq_r12];
        R[arm_lr] = R[arm_fiq_r14];
        R[arm_sp] = R[arm_fiq_r13];
        R[arm_spsr] = R[arm_fiq_spsr];
    }
    else if(newmode==arm_mode_irq){
        //进入irq模式
        R[arm_lr] = R[arm_irq_r14];
        R[arm_sp] = R[arm_irq_r13];
        R[arm_spsr] = R[arm_irq_spsr];
    }
    else if(newmode==arm_mode_und){
        //进入und模式
        R[arm_lr] = R[arm_und_r14];
        R[arm_sp] = R[arm_und_r13];
        R[arm_spsr] = R[arm_und_spsr];
    }
    else if(newmode==0b11111){
        //进入用户模式
        if(oldmode!=arm_mode_fiq){
            //非fiq模式,复制sp,lr
            //一般除了pc都复制,由指令来还原pc
            R[arm_r0 + 13] = R[arm_save_r0 + 13];
            R[arm_r0 + 14] = R[arm_save_r0 + 14];
            R[arm_spsr] = R[arm_save_r0 + arm_spsr];
        }
        else{
            //一般不会出现
            //fiq模式
            R[arm_r0 + 8] = R[arm_save_r0 + 8];
            R[arm_r0 + 9] = R[arm_save_r0 + 9];
            R[arm_r0 +10] = R[arm_save_r0 +10];
            R[arm_r0 +11] = R[arm_save_r0 +11];
            R[arm_r0 +12] = R[arm_save_r0 +12];
            R[arm_r0 +13] = R[arm_save_r0 +13];
            R[arm_r0 +14] = R[arm_save_r0 +14];
            R[arm_spsr] = R[arm_save_r0 + arm_spsr];
        }
    }
    if(R[arm_save_r0+13]==0x3007f88){
        R[arm_save_r0+13] = 0x11;
    }
    R[arm_nflag] = (R[arm_cpsr]>>31)&1;
    R[arm_zflag] = (R[arm_cpsr]>>30)&1;
    R[arm_cflag] = (R[arm_cpsr]>>29)&1;
    R[arm_vflag] = (R[arm_cpsr]>>28)&1;
    R[arm_qflag] = (R[arm_cpsr]>>27)&1;
    R[arm_iflag] = (R[arm_cpsr]>>7)&1;
    R[arm_fflag] = (R[arm_cpsr]>>6)&1;
    R[arm_tflag] = (R[arm_cpsr]>>5)&1;
}

typedef void (*thumb_fn_t)(uint32_t*R,uint32_t insn);
extern const thumb_fn_t thumb_fns[];

static void thumb_fast(uint32_t*R,uint16_t insn){
    if(thumb_fns[insn]){
        thumb_fns[insn](R,insn);
    }
    else if(
        (insn&(0b11111<<11))==(0b11110<<11)
    ){
        //bl
        #if 1
        int s = (insn>>10) & 1;
        int imm10 = insn&0x3ff;
        R[arm_nextPc] += 2;
        R[arm_pc] += 2;
        insn = read_u16(R,R[arm_nextPc]);
        int j1 = (insn>>13) & 1;
        int j2 = (insn>>11) & 1;
        int imm11 = insn&0x7ff;
        int i1 = ~(j1 ^ s)&1;
        int i2 = ~(j2 ^ s)&1;
        int32_t imm = imm11|(imm10<<11)|(i2<<21)|(i1<<22)|(s<<23);
        imm<<=8;
        imm>>=7;    //s:i1:i2:imm10:imm11:0
        R[arm_lr] = ((R[arm_pc]-2)&~1)|1;
        R[arm_pc] += imm - 2 + 1;
        R[emu_state] |= (1<<EMU_STATE_JMPPC);
        if(R[emu_state]&(1<<EMU_STATE_HARDWARE)){
            R[arm_pc] |= 1;
        }
        #else
        return t_bl(R,insn);
        #endif
    }
    else{
        //可能是跳转
        fprintf(stderr,"err insn:%08X",R[arm_pc]);
    }
}

static int arm_cond(uint32_t*R,int cond){
    int ret = 0;
    switch (cond)
    {

    case 0x0:/*eq*/ ret = R[arm_zflag];break;
    case 0x1:/*ne*/ ret = R[arm_zflag]==0;break;
    case 0x2:/*cs*/ ret = R[arm_cflag];break;
    case 0x3:/*cc*/ ret = R[arm_cflag]==0;break;
    case 0x4:/*mi*/ ret = R[arm_nflag];break;
    case 0x5:/*pl*/ ret = R[arm_nflag]==0;break;
    case 0x6:/*vs*/ ret = R[arm_vflag];break;
    case 0x7:/*vc*/ ret = R[arm_vflag]==0;break;
    #if 0
    //旧代码
    case 0x8:/*hi*/ ret = R[arm_cflag]&&(R[arm_zflag]==0);break;
    case 0x9:/*ls*/ ret = !R[arm_cflag]||R[arm_zflag];break;
    case 0xa:/*ge*/ ret = R[arm_nflag]==R[arm_vflag];break;
    case 0xb:/*lt*/ ret = R[arm_nflag]!=R[arm_vflag];break;
    case 0xc:/*gt*/ ret = !R[arm_zflag]&&(R[arm_vflag]==R[arm_nflag]);break;
    case 0xd:/*le*/ ret = R[arm_zflag]||(R[arm_nflag]!=R[arm_vflag]);break;
    #else
    case 0x8:/*hi*/ ret = R[arm_cflag]&(~R[arm_zflag]);break;
    case 0x9:/*ls*/ ret = (~R[arm_cflag]&1)|R[arm_zflag];break;
    case 0xa:/*ge*/ ret = R[arm_nflag]==R[arm_vflag];break;
    case 0xb:/*lt*/ ret = R[arm_nflag]!=R[arm_vflag];break;
    case 0xc:/*gt*/ ret = ~R[arm_zflag]&(R[arm_vflag]==R[arm_nflag]);break;
    case 0xd:/*le*/ ret = R[arm_zflag] |(R[arm_nflag]!=R[arm_vflag]);break;
    #endif
    default:
        break;
    }
    return ret;
}
extern int frame;
extern void cpu_svc(uint32_t*R,int imm){
    /*
  BASE+00h   Reset                      Supervisor (_svc)  I=1, F=1
  BASE+04h   Undefined Instruction      Undefined  (_und)  I=1, F=unchanged
  BASE+08h   Software Interrupt (SWI)   Supervisor (_svc)  I=1, F=unchanged
  BASE+0Ch   Prefetch Abort             Abort      (_abt)  I=1, F=unchanged
  BASE+10h   Data Abort                 Abort      (_abt)  I=1, F=unchanged
  BASE+14h   (Reserved)                 -          -       -
  BASE+18h   Normal Interrupt (IRQ)     IRQ        (_irq)  I=1, F=unchanged
  BASE+1Ch   Fast Interrupt (FIQ)       FIQ        (_fiq)  I=1, F=1
    */

    uint32_t spsr = 0;
    uint32_t cpsr = 0;
    cpsr = R[arm_cpsr]&0x1f;
    cpsr |= R[arm_iflag]<<7;
    cpsr |= R[arm_fflag]<<6;
    cpsr |= R[arm_tflag]<<5;
    cpsr |= R[arm_nflag]<<31;
    cpsr |= R[arm_zflag]<<30;
    cpsr |= R[arm_cflag]<<29;
    cpsr |= R[arm_vflag]<<28;
    cpsr |= R[arm_qflag]<<27;

    R[arm_svc_r14] = R[arm_pc] - (4>>R[arm_tflag]);
    //设置当前cpsr,和irq的spsr
    R[arm_pc] = 0x8;
    R[arm_svc_spsr] = cpsr;
    R[arm_cpsr] = arm_mode_svc;
    R[arm_cpsr] |= 1<<7;    //iflag
    R[emu_state] |= (1<<EMU_STATE_JMPPC);
    return;
}

static void irq_set(xgba_t*gba){
    uint32_t spsr = gba->R[arm_cpsr]&0x1f;
    spsr |= gba->R[arm_iflag]<<7;
    spsr |= gba->R[arm_fflag]<<6;
    spsr |= gba->R[arm_tflag]<<5;
    spsr |= gba->R[arm_nflag]<<31;
    spsr |= gba->R[arm_zflag]<<30;
    spsr |= gba->R[arm_cflag]<<29;
    spsr |= gba->R[arm_vflag]<<28;
    uint32_t cpsr = arm_mode_irq;
    cpsr |= 1<<7;   //iflag

    //thumb模式需要+2偏移
    if(gba->R[arm_tflag]){
        cpsr |= 0x10;
    }
    gba->R[arm_irq_r14] = gba->R[arm_pc] + (gba->R[arm_tflag]<<1);
    //设置当前cpsr,和irq的spsr
    gba->R[arm_pc] = 0x18;  //设置irq pc
    gba->R[arm_irq_spsr] = spsr;
    //切换成irq模式,开启iflag
    gba->R[arm_cpsr] = cpsr;
    gba->R[emu_state] |= (1<<EMU_STATE_JMPPC);
}

static void set_io(xgba_t*gba,uint32_t address,uint32_t value,int size){
    uint16_t oldvalue = *(uint16_t*)(gba->io+(address&0xfff));
    if(size==1){
        oldvalue = *(uint8_t*)(gba->io+(address&0xfff));
    }
    else if(size==4){
        oldvalue = *(uint32_t*)(gba->io+(address&0xfff));
    }
    switch (address&0xfff)
    {
    case 0x00:{
        /*DISPCNT*/
    }break;
    case 0x04:{
        //
        value &= ~7;    //有上位不可写
        value |= (oldvalue&7);
    }
    break;
    case 0x06: {/*VCOUNT*/ /*只读*/ value = oldvalue;} break;
    case 0x130:{/*KEYINPUT*/ /*只读*/ value = oldvalue;} break;
    case 0x202:{
        //取反
        value = oldvalue & ~value;
    }
    break;
    case 0x301:{
        gba->R[emu_state] |= 1<<(EMU_STATE_HALT+((value>>7)&1));
    }
    break;
    case 0x204:{
        int sram_wait = value&0xb11;
        int wait_0_1 = (value>>2)&0x3;
        int wait_0_2 = (value>>4)&0x1;
        int wait_1_1 = (value>>5)&0x3;
        int wait_1_2 = (value>>7)&0x1;
        int wait_2_1 = (value>>8)&0x3;
        int wait_2_2 = (value>>10)&0x1;
        int phi = (value>>11)&0x3;
        int prefetch = (value>>14)&1;

        wait_0_1 ++;
        wait_1_1 ++;
        wait_2_1 ++;
        /*16位宽*/
        gba->exec_cycles[0x8][1] = ((wait_0_1>>2)<<3) /*8,0*/ + (5 - (wait_0_1&3)) * ((wait_0_1>>2)^1);
        gba->exec_cycles[0xa][1] = ((wait_1_1>>2)<<3) /*8,0*/ + (5 - (wait_1_1&3)) * ((wait_1_1>>2)^1);
        gba->exec_cycles[0xc][1] = ((wait_2_1>>2)<<3) /*8,0*/ + (5 - (wait_2_1&3)) * ((wait_2_1>>2)^1);

        gba->exec_cycles[0x18][1] = 2 - wait_0_2;   //2,1
        gba->exec_cycles[0x1a][1] = (1-wait_1_2)<<2 + wait_1_2;   //4,1
        gba->exec_cycles[0x1c][1] = (1-wait_2_2)<<3 + wait_2_2;   //8,1

        /*32位读取rom指令,会分16位宽,然后连续读取,默认等待1个周期*/
        gba->exec_cycles[0x8][2] = gba->exec_cycles[0x8][1] + gba->exec_cycles[0x18][1] + 1;
        gba->exec_cycles[0xa][2] = gba->exec_cycles[0xa][1] + gba->exec_cycles[0x1a][1] + 1;
        gba->exec_cycles[0xc][2] = gba->exec_cycles[0xc][1] + gba->exec_cycles[0x1c][1] + 1;

        //32位连续读取,默认要等待1个周期
        gba->exec_cycles[0x18][2] = gba->exec_cycles[0x18][1]*2+1;
        gba->exec_cycles[0x1a][2] = gba->exec_cycles[0x1a][1]*2+1;
        gba->exec_cycles[0x1c][2] = gba->exec_cycles[0x1c][1]*2+1;

        //16位,后半段ROM
        gba->exec_cycles[0x9][1] =    gba->exec_cycles[0x8][1];
        gba->exec_cycles[0x9+2][1] =  gba->exec_cycles[0x8+2][1];
        gba->exec_cycles[0x9+4][1] =  gba->exec_cycles[0x8+4][1];
        gba->exec_cycles[0x19][1] =   gba->exec_cycles[0x18][1];
        gba->exec_cycles[0x19+2][1] = gba->exec_cycles[0x18+2][1];
        gba->exec_cycles[0x19+4][1] = gba->exec_cycles[0x18+4][1];

        //32位,后半段ROM
        gba->exec_cycles[0x9][2] =    gba->exec_cycles[0x8][2];
        gba->exec_cycles[0x9+2][2] =  gba->exec_cycles[0x8+2][2];
        gba->exec_cycles[0x9+4][2] =  gba->exec_cycles[0x8+4][2];
        gba->exec_cycles[0x19][2] =   gba->exec_cycles[0x18][2];
        gba->exec_cycles[0x19+2][2] = gba->exec_cycles[0x18+2][2];
        gba->exec_cycles[0x19+4][2] = gba->exec_cycles[0x18+4][2];

    }break;
    default:
        break;
    }
    if(size==1){
        *(uint8_t*)(gba->io+(address&0xfff)) = value;
    }
    else if(size==2){
        *(uint16_t*)(gba->io+(address&0xfff)) = value;
    }
    else if(size==4){
        *(uint32_t*)(gba->io+(address&0xfff)) = value;
    }
}

int xgba_vram_render(xgba_t*gba);
extern int frame;

int xgba_loop(xgba_t*gba){
    uint32_t oldmode;
    uint32_t newmode;
    int32_t next = 0;
    uint32_t *reg = gba->R;
    gba->R[arm_nextPc] = gba->R[arm_pc];
    gba->R[arm_pc] += 8>>gba->R[arm_tflag];
    if(!gba->errorf){
        gba->errorf = (void*)fprintf;
        gba->error_data = stderr;
    }
    while(!gba->R[emu_quit]){
        do{
            if(gba->R[emu_state]&(1<<EMU_STATE_JMPPC)){
                uint32_t oldinsn = gba->R[arm_old_insn];
                gba->R[emu_state] &= ~(1<<EMU_STATE_JMPPC);
                if((oldinsn&~(0x7<<3))==0x4687){
                    //mov pc,r0
                    //thumb模式
                    gba->R[arm_pc] |= 1;
                }
                /*更新JMPPC*/
                gba->R[emu_state] &= ~(1<<EMU_STATE_JMPPC);
                //设置pc
                gba->R[arm_tflag] = gba->R[arm_pc]&1;
                gba->R[arm_pc] &= ~3 >> gba->R[arm_tflag];
                gba->R[arm_nextPc] = gba->R[arm_pc];
                gba->R[arm_pc] += 8>>gba->R[arm_tflag];
                next = 0;
            }
            gba->R[arm_pc] += next;
            gba->R[arm_nextPc] += next;

            if(gba->R[arm_nextPc]+(8>>gba->R[arm_tflag])!=gba->R[arm_pc]){
                /*有些指令未实现JMPPC状态,所以这代码是为了检查错误*/
                printf("PC:%08X\n",gba->R[arm_pc]);
            }

            uint32_t pc = gba->R[arm_nextPc];
            uint32_t insn;

            uint32_t addr = (gba->R[arm_pc]>>24)&0xf;
            addr |= gba->exec_next << 0x4;      //如果是next,则+0x10
            /*
            1S
                S = (默认1时钟周期 + 顺序等待时钟周期)
            1N
                N = (默认1时钟周期 + 非顺序等待时钟周期)

            ROM(0x08000000~)的bus宽度是16,所以当执行ROM中的arm代码,会先读取16位,接着在读取16位数据组合成32指令.读取时的指令应该为
                S+1+S     (连续读取时)
                N+1+S     (非连续读取,如跳转后的arm指令)
                这里S为连续读取,N为非连续读取
                所以执行arm代码的完整周期为
                (S+1+S) + 1
                (N+1+S) + 1
            如果是thumb指令,一般为
                1S = (S + 1)     没有内存操作
                1N = (N + 1)     非连续内存读取,或者

                一些特殊指令的周期不固定,如ldr r0,[pc,imm8]
                1S + 1N + 1I
                1I固定为1
                1S为取指令的周期,ROM里的thumb代码 1 + S                 (这里的S为WAITCNT设置的值)
                1N为访问内存的周期,一般为访问4字节 ,则为 (1 + N + S)     (同样N,S为WAITCNT设置的值,N为第一次访问的值,S为第二次访问的值.原因是ROM的bus为16位)

                1S + 1N + 1I
                当下一条指令时,执行时,应该为第一次访问
            */
            gba->R[arm_cycles] += gba->exec_cycles[addr][2>>gba->R[arm_tflag]] + 1;

            gba->exec_next += (~gba->exec_next)&1;

            oldmode = gba->R[arm_cpsr]&0x1f;

            if(gba->R[arm_lr]==0x34d){
                next = 4;
            }

            if(gba->R[arm_tflag]){
                insn = xgba_readu16(gba,pc);
                gba->R[arm_old_insn] = insn;
                thumb_fast(gba->R,insn);
                next = 2;
            }
            else{
                insn = xgba_readu32(gba,pc);
                uint32_t cond = insn>>28;
                if(cond==0xe||(arm_cond(gba->R,cond))){
                    gba->R[arm_old_insn] = insn;
                    arm_exec(gba->R,insn);
                }
                next = 4;
            }

            if(gba->R[emu_state]&(1<<EMU_STATE_JMPPC)){
                /*这段代码是为了DEBUG ARM的跳转错误*/
                if(gba->R[arm_pc]==0){
                    gba->R[arm_nextPc] = 4;
                }
                if(gba->R[arm_pc]<0x01000000){
                    // printf("PC:%08X,%08X,%08X,%08X,%08X\n",gba->R[arm_pc],gba->R[arm_nextPc],gba->R[arm_old_pc1],gba->R[arm_old_pc2]
                    // ,gba->R[arm_old_pc3]
                    // );
                }
            }

            if(gba->R[emu_state]&(1<<EMU_STATE_JMPPC)){
                /*
                一些指令会切换模式.如下列(都是arm代码)
                    svc模式
                        mov pc,lr
                        切换回spsr的模式
                    irq模式
                        sub pc,lr,#4h
                        切换会spsr的模式
                */
                uint32_t oldinsn = gba->R[arm_old_insn];
                //mov pc,lr
                if((gba->R[arm_cpsr]&0x1f)==arm_mode_svc){
                    if((oldinsn & 0x0FE0FFF0) == 0x01A0F000){
                        gba->R[arm_cpsr] = gba->R[arm_spsr];
                    }
                }
                if((gba->R[arm_cpsr]&0x1f)==arm_mode_irq){
                    if((oldinsn & 0x0FE0FFFF) == 0x0240F004){
                        //sub pc,lr,4h
                        gba->R[arm_cpsr] = gba->R[arm_spsr];
                    }
                }
            }

            newmode = gba->R[arm_cpsr]&0x1f;
            if(oldmode!=newmode){
                //切换模式
                switch_mode(gba->R,oldmode);
                oldmode = gba->R[arm_cpsr]&0x1f;
                gba->R[arm_pc] |= gba->R[arm_tflag];
            }

            /*
            现在循环执行模拟代码只需要3个条件
                1.判断执行arm代码还是thumb代码
                2.判断是否打断流水线.(JMPPC状态)
                3.整体的虚拟cpu状态,(emu_state)
                    emu_state包含
                        EMU_STATE_IO_WRITE (0x04xxxxxx的内存访问)
                        EMU_STATE_HALT     (0x04000301写入1,时cpu进入停止状态)
                        EMU_STATE_HARDWARE (一般是触发hblank中断)

                do{
                    if(emu_state&JMPPC){
                        update_pc
                    }
                    if(R[tflag])
                        thumb();
                    else
                        arm();
                    emu_state += exec_cycles;
                }while(emu_state);
            */

           /*
           实际上最理想的状态性格是
            do{
                if(R[tflag])
                    thumb();
                else
                    arm();
                emu_state += exec_cycles;
                DODMA0
                DODMA1
                DODMA2
                DODMA3
            }while(emu_state);

            应该省略emu_state&JMPPC,然后添加emu_state&UPDATE_CPSR 模式
            DODMA0 应该是一个宏,
                dma_dest[cycles>>shift_base * next_dma] = dma_src[cycles>>shift_base];
                当时钟溢出时,偏移位置往后偏移一个位置.优点如下
                    实时计算,实时复制.
                    计算音频时钟非常精准
                缺点
                    需要机器内存频率高.如果有缓存机制,则性能高.如果没有缓存机制,性能需要接近 (16.6 * 4) MB/S

                注:有时候,需要高性能模式的时候,需要设置内存实时写入,改用emu_state&DODMA
                注:DODMA1,DODMA2,在更多的时候是为了处理音频.需要搭配timer0,timer1,
                    这时需要把dma_dest设置为声道1或2的目标缓存
                    还需要计算cycles的增量,来处理音频

           */

            /*
            当下一行的代码
                while()
                的条件是除了EMU_STATE_JMPPC外的所有位都为空.
                实际上当是JMPPC状态时,并不是打乱结构,所以会跳回do起始部分检查JMPPC状态,并更新流水线状态

                但有时候JMPPC和EMU_STATE_HARDWARE(主要是hblank状态)同时触发.这时需要更新pc和nextPc状态
            */
        }while(!((gba->R[emu_state]&~(1<<EMU_STATE_JMPPC))>>EMU_STATE_SHIFT_BASE));

        if(gba->R[emu_state]&(1<<EMU_STATE_MEMACCESS_ERR)){
            /*内存访问错误*/
            gba->errorf(gba->error_data,"PC:%08X",gba->R[arm_nextPc]);
            return -1;
        }

        if(gba->R[emu_state]&(1<<EMU_STATE_JMPPC)){
            uint32_t oldinsn = gba->R[arm_old_insn];
            gba->R[emu_state] &= ~(1<<EMU_STATE_JMPPC);
            if((oldinsn&~(0x7<<3))==0x4687){
                //mov pc,r0
                //thumb模式
                gba->R[arm_pc] |= 1;
            }
            /*更新JMPPC*/
            gba->R[emu_state] &= ~(1<<EMU_STATE_JMPPC);
            //设置pc
            gba->R[arm_tflag] = gba->R[arm_pc]&1;
            gba->R[arm_pc] &= ~3 >> gba->R[arm_tflag];
            gba->R[arm_nextPc] = gba->R[arm_pc];
            gba->R[arm_pc] += 8>>gba->R[arm_tflag];

            next = 4>>gba->R[arm_tflag];
            gba->R[arm_pc] -= next;
            gba->R[arm_nextPc] -= next;
        }

        int oldVcount = VCOUNT;

        /*处理io寄存器,可能会影响EMU_STATE_HALT,EMU_STATE_STOP*/
        if(gba->R[emu_state]&(1<<EMU_STATE_IO_WRITE)){
            gba->R[emu_state] &= ~(1<<EMU_STATE_IO_WRITE);
            uint32_t address = gba->R[emu_write_address];
            uint32_t value = gba->R[emu_write_value];
            uint32_t sz = gba->R[emu_write_type];
            set_io(gba,address,value,sz);
        }
        if(gba->R[emu_state]&(1<<EMU_STATE_HALT)){
            //一般为是等待垂直中断(swi 5)后,这个中断就会被执行
            //应该是等待各种中断
            gba->R[emu_state] &= ~(1<<EMU_STATE_HALT);

            //绘制vram
            gba->screen_line = VCOUNT;
            //vram绘制
            xgba_vram_render(gba);

            gba->R[emu_state] >>= EMU_STATE_HARDWARE;
            gba->R[emu_state] <<= EMU_STATE_HARDWARE;
            gba->R[emu_state] |= (1<<EMU_STATE_HARDWARE);
        }

        if(gba->R[emu_state]&(1<<EMU_STATE_HARDWARE)){
            //现在暂时hblank
            //reg[arm_cycles] = 0;
            uint32_t mask = 1<<(EMU_STATE_HARDWARE+1);
            mask -= 1;
            int32_t cycles = //1<<EMU_STATE_HARDWARE;  //计算下一个溢出
                gba->R[arm_cycles]&mask;
            gba->R[emu_state] &= ~mask;    //保存其他的事件位
            cycles -= hblank_clock * 0x20;
            gba->R[emu_state] |= cycles;    //异或这些数据
            gba->screen_line = VCOUNT;
            if(gba->screen_line<160){
                gba->io[4] &= ~1;   //不处理垂直空白
                xgba_vram_render(gba);
            }
            else{
                gba->io[4] |= 1;    //垂直空白期间
            }
            VCOUNT += 1;

            //VCOUNT
            gba->io[4] &= ~4;
            gba->io[4] |= (VCOUNT==gba->io[5])<<2;

            //HBlank
            gba->io[4] &= ~2;
            gba->io[4] |= 2;
            gba->io[0x202] |= 0x2;

            if(VCOUNT>227){
                VCOUNT = 0;
                if(gba->render){
                    gba->render(gba);
                }
            }
        }

        if(VCOUNT==160&&oldVcount!=VCOUNT
            //&&isvblank /*这个表示只能在swi 5模式*/
            ){

            if(!gba->R[arm_iflag]
            &&gba->io[0x4]&0x8
            &&gba->io[0x200]&1
            ){
                //vblank
                gba->io[0x202] |= 1;
                irq_set(gba);
            }
            else{
                //如果设置了
            }
            if(gba->render){
                gba->render(gba);
            }
        }
        else if(
            gba->io[0x4]&0x10
            &&!gba->R[arm_iflag]
            &&(*(uint16_t*)&gba->io[0x200]&*(uint16_t*)&gba->io[0x202])
        ){
            //hblank
            irq_set(gba);
        }
        int newmode = gba->R[arm_cpsr]&0x1f;
        if(oldmode!=newmode){
            switch_mode(gba->R,oldmode);
            oldmode = gba->R[arm_cpsr]&0x1f;
        }

    }
}
